﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Reflection;
using System.Web.Mvc;
using System.Web.UI;
using System.IO;
using System.Web.Caching;

namespace Domzs.Web.Mvc
{
    public class ActionOutputCacheAttribute : ActionFilterAttribute
    {
        // Fields
        private int _cacheDuration;
        private string _cacheKey;
        private TextWriter _originalWriter;
        private static MethodInfo _switchWriterMethod = typeof(HttpResponse).GetMethod("SwitchWriter", BindingFlags.NonPublic | BindingFlags.Instance);

        // Methods
        public ActionOutputCacheAttribute(int cacheDuration)
        {
            this._cacheDuration = cacheDuration;
        }

        private string ComputeCacheKey(ActionExecutingContext filterContext)
        {
            StringBuilder builder = new StringBuilder();
            foreach (KeyValuePair<string, object> pair in filterContext.RouteData.Values)
            {
                builder.AppendFormat("rd{0}_{1}_", pair.Key.GetHashCode(), pair.Value.GetHashCode());
            }
            foreach (KeyValuePair<string, object> pair2 in filterContext.ActionParameters)
            {
                builder.AppendFormat("ap{0}_{1}_", pair2.Key.GetHashCode(), pair2.Value.GetHashCode());
            }
            return builder.ToString();
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            this._cacheKey = this.ComputeCacheKey(filterContext);
            string str = (string)filterContext.HttpContext.Cache[this._cacheKey];
            if (str != null)
            {
                ContentResult result = new ContentResult();
                result.Content = str;
                filterContext.Result = result;
            }
            else
            {
                this._originalWriter = (TextWriter)_switchWriterMethod.Invoke(HttpContext.Current.Response, new object[] { new HtmlTextWriter(new StringWriter()) });
            }
        }

        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            if (this._originalWriter != null)
            {
                HtmlTextWriter writer = (HtmlTextWriter)_switchWriterMethod.Invoke(HttpContext.Current.Response, new object[] { this._originalWriter });
                string s = ((StringWriter)writer.InnerWriter).ToString();
                filterContext.HttpContext.Response.Write(s);
                filterContext.HttpContext.Cache.Add(this._cacheKey, s, null, DateTime.Now.AddSeconds((double)this._cacheDuration), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
            }
        }
    }


}
